import math
import re
from datetime import datetime

from odoo import fields, models, api, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import config

qt = False


class PlaceOrderLineWizard(models.TransientModel):
    _name = "place.order.line.wizard"
    _description = "Place Order Line"

    pow_id = fields.Many2one('place.order.wizard', string="Place Order Line")
    po_line = fields.Char(string="PO Line", default=lambda self: self._get_po_line())
    qt = fields.Boolean(string="QTA", default=lambda self: self._get_qta())
    qty = fields.Integer(string="QTY", default=lambda self: self.env.context.get('qty', 0))
    unit_price = fields.Float(string='Unit Price', compute="_compute_unit_price", digits=(16, 4), readonly=False, store=True)
    nre = fields.Float(string='NRE', digits=(16, 3), default=lambda self: self.env.context.get('nre', 0))
    extra_charge = fields.Float(string='Additional Charge', digits=(16, 3))
    customer_dd = fields.Date(string='Customer DD', default=lambda self: fields.Date.today())

    materiel_status = fields.Selection([
        ('S', 'NPI'),
        ('P', 'MP'),
        ('T', 'Test')
    ], string='Product Status', default=lambda self: self._get_materiel_status())
    special_order_type = fields.Selection([
        ('eq_only', 'EQ only'),
        ('free_cost', 'Free cost'),
        ('wb', 'WB')
    ], string="Special OT")
    total_price = fields.Float(string="Total Amount", readonly=False, digits=(16, 3))
    origin_price = fields.Float(string="Origin Price")

    def _get_materiel_status(self):
        pn = self.env.context.get('pn')
        if pn:
            pn_id = self.env['customer.item.code'].search([('code', '=', pn)], limit=1)
            if pn_id:
                product_template = pn_id.product_id
                if product_template.materiel_status:
                    status = product_template.materiel_status
                    if status == 'Q':
                        return 'S'
                    else:
                        return status
        else:
            return False

    def _get_qta(self):
        pn = self.env.context.get('pn')
        if pn:
            pn_id = self.env['customer.item.code'].search([('code', '=', pn)], limit=1)
            if pn_id:
                product_template = pn_id.product_id
                if product_template.materiel_status:
                    status = product_template.materiel_status
                    if status == 'Q':
                        return True
                    else:
                        return False

    @api.onchange('qty')
    def _get_po_line(self):
        polw_len = self.env.context.get('polw_len')
        self.po_line = str(polw_len).zfill(2)

    @api.onchange('qty', 'unit_price')
    def _compute_total_price(self):
        self.total_price = self.qty * self.unit_price

    @api.onchange('qty')
    def _compute_unit_price(self):
        if self.qty <= 0:
            self.unit_price = 0
        for line in self:
            # 获取关联的 CRM 报价信息
            crm_order = line.pow_id.crm_id
            if crm_order:
                # 获取按数量排序的报价信息
                crm_lines = crm_order.quotation_lines.sorted(key=lambda r: r.qty, reverse=True)
                # 根据数量选择价格
                for crm_line in crm_lines:
                    line.unit_price = crm_line.unit_price
                    if line.qty >= crm_line.qty:
                        line.unit_price = crm_line.unit_price
                        line.nre = crm_line.nre if line.pow_id.order_type == 'new' else 0
                        # line.extra_charge = crm_line.tooling_cost
                        break

    @api.constrains("qty", "unit_price", 'origin_price')
    def _check_qty_unit_price(self):
        for res in self:
            if res.qty <= 0 and res.special_order_type != 'eq_only':
                raise ValidationError(_("Quantity must be greater than zero,but except for the EQ Only.😶"))
            if res.unit_price <= 0 and res.special_order_type not in ['free_cost', 'eq_only']:
                raise ValidationError(_("Except for 'Free Cost' and 'EQ Only', the unit price is not allowed to be 0.🤐"))


class PlaceOrderWizard(models.TransientModel):
    _name = "place.order.wizard"
    _description = "Place Order"

    customer_id = fields.Many2one('res.partner', string="Code",
                                  default=lambda self: self.env.context.get('customer_id', False))
    s_special_customer = fields.Boolean(string="Special Customer", related="customer_id.s_special_customer")
    crm_id = fields.Many2one('crm.lead', default=lambda self: self.env.context.get('crm_id', False))
    po = fields.Char(string="PO", default=lambda self: self.env.context.get('po', False))
    s_simi_fg = fields.Boolean('Semi-FG', default=lambda self: self.env.context.get('s_simi_fg', False))
    order_type = fields.Selection([
        ('new', 'NEW'),
        ('repeat', 'REPEAT'),
        ('change', 'CHANGE')
    ], string="Order Type", default=lambda self: self.env.context.get('order_type', 'new'))
    pn = fields.Many2one('customer.item.code', string="PN")
    pn_rev = fields.Char(related="pn.version", string="PN REV")
    recent_price = fields.Float('Recent Price', related="pn.recent_price", digits=(16, 4))
    customer_item_desc = fields.Char(related="pn.customer_item_desc", string="PN Desc.")
    mpn_id = fields.Many2one('product.template', compute="_compute_mpn_id", string="MPN", store=True, readonly=False)
    shipping_address_id = fields.Many2one('res.partner', string="Shipping Address",
                                          domain="[('parent_id', '=', customer_id), ('type', '=', 'delivery')]",
                                          default=lambda self: self.env.context.get('contact_id', False))
    inventory_number = fields.Integer(string="Inventory number")
    in_process_number = fields.Integer(string="Numbers in process")
    new_pn = fields.Char(string='PN', default=lambda self: self.env.context.get('pn', False))
    new_pn_rev = fields.Char(string='PN REV', default=lambda self: self.env.context.get('new_pn_rev', False))
    pn_description = fields.Char(string='PN Description',
                                 default=lambda self: self.env.context.get('pn_description', False))
    application_product_id = fields.Many2one('application.product', string="PCB Application",
                                             default=lambda self: self.env.context.get('application_product_id', False))

    new_mpn_id = fields.Many2one('product.template', string="MPN",
                                 default=lambda self: self.env.context.get('new_mpn_id', False))
    customer_currency = fields.Many2one("res.currency", compute="_compute_customer_currency", string="Currency",
                                        store=True)
    incoterm = fields.Many2one('account.incoterms', string="Incoterm")
    remark = fields.Text(string="Remark")
    polw_ids = fields.One2many('place.order.line.wizard', 'pow_id', string="Place Order Line")
    polw_len = fields.Integer(string="PO Line", default=lambda self: self._get_polw_len())
    po_verify_value = fields.Boolean(string="PO Verify Value", compute='_po_verify_value')
    end_bool = fields.Boolean(string="End Customer", default=False)
    end_po = fields.Char(string="End PO")
    end_pn = fields.Char(string="End PN")
    end_pn_rev = fields.Char(string="End PN REV")
    special_type = fields.Boolean(string="Special", default=lambda self: self.env.context.get('special_type', False))  # 用作来自哪个page
    exist_mpn_bl = fields.Boolean(string="Exist MPN", default=False)
    exist_mpn = fields.Many2one('product.template', string="MPN")
    warning_label = fields.Char(string="Warning")
    special_order_type = fields.Boolean(string="Special Order", compute='_compute_special_order_type')

    # @api.onchange('new_pn')
    # def _onchange_new_pn(self):
    #     if self.new_pn:
    #         item_code = self.env['customer.item.code'].search([('code', '=', self.new_pn), ('customer_id', '=', self.customer_id.id)])
    #         if item_code:
    #             self.new_pn = False
    #             return {
    #                 'warning': {
    #                     'title': _("Warning"),
    #                     'message': _("This PN already exists in this customer, please change another one!😶")
    #                 }
    #             }

    @api.onchange('polw_ids')
    def _get_polw_len(self):
        self.polw_len = len(self.polw_ids)

    @api.onchange('polw_ids', 'polw_ids.special_order_type')
    def _compute_special_order_type(self):
        for line in self:
            if line.polw_ids:
                for polw in line.polw_ids:
                    if polw.special_order_type:
                        line.special_order_type = True
                        return
            line.special_order_type = False

    @api.onchange('exist_mpn', 'customer_id', 'exist_mpn_bl')
    def onchange_exist_mpn(self):
        if self.exist_mpn and self.customer_id:
            item_code = self.env['customer.item.code'].search([('product_id', '=', self.exist_mpn.id)])
            if item_code:
                self.pn_description = item_code[0].customer_item_desc
                self.new_pn = item_code[0].code
                self.new_pn_rev = item_code[0].version
                item_code = self.env['customer.item.code'].search([('product_id', '=', self.exist_mpn.id), ('customer_id', '=', self.customer_id.id)])
                if item_code:
                    self.warning_label = (_(f"This customer already has PN %s in the MPN modification") % item_code[0].code)
                else:
                    self.warning_label = False

    @api.onchange('pn')
    def onchange_pn(self):
        if self.pn:
            self.crm_id = self.pn.product_id.crm_id

    @api.depends('pn')
    def _compute_mpn_id(self):
        if self.pn:
            self.mpn_id = self.pn.product_id.id
        else:
            self.mpn_id = False

    @api.onchange('customer_id')
    def _compute_incoterm(self):
        if self.customer_id:
            if not self.s_simi_fg:
                self.s_simi_fg = self.customer_id.s_goods_type == 'semi_fg'
            if self.customer_id.shipping_child_ids:
                self.shipping_address_id = self.customer_id.shipping_child_ids[0].id
            else:
                self.shipping_address_id = False
        else:
            self.shipping_address_id = False

    @api.onchange('shipping_address_id')
    def _onchange_shipping_address_id(self):
        if self.shipping_address_id.incoterm:
            self.incoterm = self.shipping_address_id.incoterm.id
        else:
            self.incoterm = False

    @api.depends('customer_id', 'customer_id.property_product_pricelist')
    def _compute_customer_currency(self):
        for re in self:
            re.customer_currency = re.customer_id.property_product_pricelist.currency_id.id

    @api.onchange('po')
    @api.depends('po')
    def _po_verify_value(self):
        """搜索下单中存在同样的po"""
        if not self.po:
            self.po_verify_value = True
            return
        sale_order = self.env['sale.order'].search([('po', '=', self.po)])
        if sale_order:
            self.po_verify_value = False
        else:
            self.po_verify_value = True

    def confirmation(self):
        """确认下单"""
        # 字段检查
        self.sudo()
        if not self.customer_id:
            raise UserError(_("Customer Code Not filled. 😒"))
        if not self.po:
            raise UserError(_("PO Not filled. 😒"))
        if self.order_type == 'new' and not self.crm_id and not self.s_special_customer and not self.exist_mpn_bl and not self.special_order_type:
            raise UserError(_('For non-special order types and non-special customers, new orders need to be placed from the quotation page 👩‍🏫'))
        if self.order_type == 'new' and self.exist_mpn_bl:
            if not self.exist_mpn:
                raise UserError(_("Please select existing mpn 😒"))
        if not self.order_type:
            raise UserError(_("Order Type Description Not filled 😒"))
        if not self.mpn_id and self.order_type != 'new':
            raise UserError(_("MPN Not filled 😒"))
        if not self.polw_ids:
            raise UserError(_("PoList Not filled 😒"))
        if not self.shipping_address_id:
            raise UserError(_("Shipping Address Not filled 😅"))
        if self.customer_id.is_virtual_customer:
            raise UserError(_('Please change the customer to a official customer first 🤬🤬🤬🤬🤬🤬!!! '))
        product_tm_id = self.get_product_template()
        first_polw = self.polw_ids[0]
        if first_polw.materiel_status == 'T':
            tt = self.with_context(lang='en_US').env['sb.workflow.template'].search([('name', '=', 'For Test PCB Approval')], limit=1)
            ap_tp = tt.id if tt else False
        else:
            st = self.env['sb.workflow.template'].search([('name', '=', 'Standard MO Approval')], limit=1).id
            ap_tp = st if st else False
        product_tm_id.write({
            'materiel_status': 'Q' if first_polw.materiel_status == 'S' and first_polw.qt else first_polw.materiel_status,
        })
        num = 1
        crm_id = False
        # 检查 self.crm_id 是否存在
        if self.crm_id:
            crm_id = self.crm_id.id
        elif product_tm_id and product_tm_id.crm_id:
            crm_id = product_tm_id.crm_id.id
        else:
            # 如果 self.pn.code 存在，尝试通过名称查找 crm.lead 记录
            if self.pn and self.pn.code:
                crm_lead = self.env['crm.lead'].search([('name', '=', self.pn.code)], limit=1)
                if crm_lead:
                    crm_id = crm_lead.id

        if not product_tm_id.crm_id and crm_id:
            # 产品关联crm
            product_tm_id.write({
                'crm_id': crm_id
            })
        # 查找pcs/set
        pcs_in_set = 1
        e_pcs_in_set = product_tm_id.uom_value_ids.filtered(lambda x: x.uom_id.name == "SET").uom_value
        qt = self.env['crm.lead'].browse(crm_id) if crm_id else product_tm_id.crm_id
        if e_pcs_in_set and e_pcs_in_set > 0:
            pcs_in_set = e_pcs_in_set
        elif qt and qt.pcs_in_panel > 0:
            pcs_in_set = qt.pcs_in_panel
        for polw in self.polw_ids:
            if pcs_in_set and polw.qty % pcs_in_set != 0:
                suggested = math.ceil(polw.qty / pcs_in_set) * pcs_in_set
                raise ValidationError(
                    f"Line {polw.po_line}: Quantity {polw.qty} must be a multiple of {pcs_in_set}. "
                    f"Suggested quantity: {suggested}."
                )
        new_sale_ids = []
        name = self.env['ir.sequence'].next_by_code('sale.order')
        item_code = self.pn or product_tm_id.customer_item_code_ids
        if self.order_type == 'new' and self.exist_mpn_bl:
            item_code = self.env['customer.item.code'].sudo().create({
                'customer_id': self.customer_id.id,
                'code': self.new_pn,
                'version': self.new_pn_rev,
                'product_id': product_tm_id.id,
                'customer_item_desc': self.pn_description,
                'recent_price': self.polw_ids[0].unit_price if len(self.polw_ids) > 0 else None,
            })
            product_tm_id.customer_item_code_ids = [(4, item_code.id)]
        for x in self.polw_ids:
            try:
                order_type = self.order_type  # 仅有第一单是创建新单, 其他均为返单
                if len(new_sale_ids) > 0 and order_type == 'new':
                    order_type = 'repeat'
                new_name = "{}-0{}".format(name, str(num).zfill(2))  # 两位拼接
                new_sale_id = self.env['sale.order'].sudo().create({
                    'partner_id': self.customer_id.id,
                    'special_order_type': x.special_order_type,
                    'po': self.po,
                    'commitment_date': x.customer_dd,
                    'name': new_name if len(self.polw_ids) > 1 else name + '-001',
                    'partner_shipping_id': self.shipping_address_id.id,
                    'incoterm': self.incoterm.id,
                    'order_type': order_type,
                    'note': self.remark,
                    'opportunity_id': crm_id,  # 官方有个字段记录哪个商机
                    'sb_workflow_template_id': ap_tp,
                    'user_id': self.customer_id.user_id.id if self.customer_id.user_id else False,
                })
                if self.end_bool:
                    new_sale_id.write({
                        # 'end_customer': self.end_customer,
                        'end_po': self.end_po,
                        'end_pn': self.end_pn,
                        'end_pn_rev': self.end_pn_rev,
                    })
                num += 1
                product_pr_id = self.env['product.product'].sudo().search(
                    [('product_tmpl_id', '=', product_tm_id.id)])
                self.env['sale.order.line'].sudo().create({
                    'order_id': new_sale_id.id,
                    'po_line': x.po_line,
                    'po': self.po,
                    's_qt': x.qt,
                    's_materiel_status': x.materiel_status,
                    'product_template_id': product_tm_id.id,
                    'product_id': product_pr_id.id,
                    'product_uom_qty': x.qty,
                    'price_unit': x.unit_price,
                    'origin_price': x.origin_price,
                    'name': product_tm_id.name,
                    'product_uom': product_tm_id.uom_id.id,
                    'tax_id': self.customer_id.tax_ids.ids,
                    's_customer_item_code': item_code.id
                })
                item_code.write({
                    'recent_price': x.unit_price
                })
                if x.nre > 0:
                    self.env['sale.order.line'].sudo().create({
                        'order_id': new_sale_id.id,
                        'product_template_id': self.env.ref('sb_sale.nre_server_product').id,
                        'product_id': self.env.ref('sb_sale.nre_server_product').product_variant_id.id,
                        'product_uom_qty': 1,
                        'price_unit': x.nre,
                        'name': 'NRE',
                        'po': self.po,
                        'tax_id': self.customer_id.tax_ids.ids
                    })
                if x.extra_charge > 0:
                    self.env['sale.order.line'].sudo().create({
                        'order_id': new_sale_id.id,
                        'product_template_id': self.env.ref('sb_sale.extra_charge_server_product').id,
                        'product_id': self.env.ref('sb_sale.extra_charge_server_product').product_variant_id.id,
                        'product_uom_qty': 1,
                        'po': self.po,
                        'price_unit': x.extra_charge,
                        'name': 'Additional Charge',
                        'tax_id': self.customer_id.tax_ids.ids
                    })
                new_sale_ids.append(new_sale_id.id)
            except Exception as e:
                raise UserError(_("Error: %s") % e)

        if len(new_sale_ids) == 1:
            return {
                'name': 'Sale Order',
                'type': 'ir.actions.act_window',
                'res_model': 'sale.order',
                'view_mode': 'form',
                'res_id': new_sale_ids[0],
                'target': 'current',
            }
        else:
            return {
                'name': 'Sale Order',
                'type': 'ir.actions.act_window',
                'res_model': 'sale.order',
                'view_mode': 'tree,form',
                'domain': [('id', 'in', new_sale_ids)],
                'target': 'current',
            }

    def get_product_template(self):
        if self.order_type != 'new':
            return self.mpn_id
        elif self.order_type == 'new' and self.exist_mpn_bl and self.exist_mpn:
            return self.exist_mpn
        # self.new_mpn_id
        # 需要创建新的
        return self.generate_mpn()

    def generate_mpn(self):
        # 字段检查
        if not self.application_product_id:
            raise UserError(_("PCB Application Not filled"))
        if not self.customer_id:
            raise UserError(_("Customer Code Not filled"))
        if not self.new_pn:
            raise UserError(_("PN Not filled"))
        if not self.new_pn_rev:
            raise UserError(_("PN REV Not filled"))
        if not self.pn_description:
            raise UserError(_("PN Description Not filled"))
        if not self.po:
            raise UserError(_("PO Description Not filled"))
        if not self.order_type:
            raise UserError(_("Order Type Description Not filled"))
        uom_id = self.env['uom.uom'].sudo().search([('name', '=', 'PCS')], limit=1)
        # 产品创建
        # 直接组成default_code
        seq = 'product_template.default_code' if not self.s_simi_fg else 'product_template.simi_fg_default_code'
        seq_next = self.env['ir.sequence'].sudo().next_by_code(seq)

        new_product_id = self.env['product.template'].sudo().create({
            'name': 'new',
            'purchase_ok': True,
            'sale_ok': True,
            'detailed_type': 'product',
            'categ_id': self.env.ref('sb_sale.finished_product_type').id if not self.s_simi_fg else 465,
            'route_ids': [self.env.ref('mrp.route_warehouse0_manufacture').id],
            'tracking': 'lot',
            'uom_id': uom_id.id or 1,
            'uom_po_id': uom_id.id or 1,
            "application_product_id": self.application_product_id.id,
            'default_code': 'W' + seq_next + 'A0',
            'versions': 'A0'
        })
        new_product_id.is_manufacture = True
        new_product_id._init_uov_records()
        # 客户部件信息创建
        new_pn_id = self.env['customer.item.code'].sudo().create({
            'customer_id': self.customer_id.id,
            'code': self.new_pn,
            'version': self.new_pn_rev,
            'product_id': new_product_id.id,
            'customer_item_desc': self.pn_description,
            'recent_price': self.polw_ids[0].unit_price if len(self.polw_ids) > 0 else None,
        })
        new_product_id.customer_item_code_ids = [(4, new_pn_id.id)]
        new_product_id.name = new_product_id.default_code if new_product_id.active else new_product_id.before_approval_code
        return new_product_id
        # return {
        #     'name': 'Create New Order',
        #     'type': 'ir.actions.act_window',
        #     'res_model': 'place.order.wizard',
        #     'view_mode': 'form',
        #     'target': 'new',
        #     'context': {'customer_id': self.customer_id.id,
        #                 'po': self.po,
        #                 'application_product_id': self.application_product_id.id,
        #                 'new_pn': self.new_pn,
        #                 'new_pn_rev': self.new_pn_rev,
        #                 'pn_description': self.pn_description,
        #                 'new_mpn_id': new_product_id.id,
        #                 'shipping_address_id': self.shipping_address_id.id,
        #                 'delivery_date': datetime.now().date()
        #                 },
        # }
